﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArch.Utils;
using TopologySearch;

namespace YJKArch.EditFloor
{
	public class FloorSpliter
	{
		public FloorSpliter(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_doc = this.m_Revit.Application.ActiveUIDocument.Document;
			this.m_ActiveView = this.m_Revit.Application.ActiveUIDocument.ActiveView;
			this.m_FloorEditCommon = new FloorEditCommon(cmdData);
		}

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Split(ref string message)
		{
			foreach (ThicknessOfEdgeInfo thicknessOfEdgeInfo in new PoleEndInterimCreator(this.m_Revit.Application).GetPoleEndInterimListByColumn(true))
			{
				Curve item = thicknessOfEdgeInfo.ConvertTo(this.m_Revit.Application.Application);
				this.m_InterimCurveList.Add(item);
			}
			SplitFloorForm splitFloorForm = new SplitFloorForm();
			splitFloorForm.Show(CmdAutoSplitFloor._hWndRevit);
			splitFloorForm.Refresh();
			int wMsg = 7;
			FloorSpliter.SendMessage(CmdAutoSplitFloor._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Result result;
			try
			{
				List<UtilityTools.ThicknessOfEdgeInfoEx> docWallBeamCenterCvInfos = UtilityTools.GetDocWallBeamCenterCvInfos(this.m_Revit, null);
				Floor floor = null;
				while (this.SelectFloor(ref floor))
				{
					if (this.SplitFloor(floor, splitFloorForm.TheFilterType, docWallBeamCenterCvInfos))
					{
						MessageBox.Show("楼板拆分成功。", "盈建科提示");
					}
				}
				splitFloorForm.Close();
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				splitFloorForm.Close();
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private bool SelectFloor(ref Floor floor)
		{
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				Reference reference = selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new FloorFilter(), "选择一块楼板");
				floor = (this.m_doc.GetElement(reference) as Floor);
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private bool SplitFloor(Floor floor, FilterType filterType, List<UtilityTools.ThicknessOfEdgeInfoEx> lstEdgeInfos)
		{
			List<List<Curve>> splitCurveByBoundingbox = this.GetSplitCurveByBoundingbox(floor, filterType, lstEdgeInfos);
			if (splitCurveByBoundingbox.Count == 0)
			{
				return false;
			}
			List<Opening> openingByFloor = this.m_FloorEditCommon.GetOpeningByFloor(floor.Id);
			List<List<Curve>> list = new List<List<Curve>>();
			List<List<Curve>> list2 = new List<List<Curve>>();
			this.m_FloorEditCommon.GetFloorLoopAndOpeningLoop(floor, ref list, ref list2);
			List<List<Curve>> list3 = new List<List<Curve>>();
			foreach (List<Curve> oldLoop in list2)
			{
				List<List<Curve>> subLoops = this.GetSubLoops(splitCurveByBoundingbox, oldLoop);
				list3.AddRange(subLoops);
			}
			foreach (Opening element in openingByFloor)
			{
				this.m_FloorEditCommon.DeleteElement(element);
			}
			this.CreateSubFloors(floor, splitCurveByBoundingbox, list3, list2);
			return true;
		}

		private List<List<Curve>> GetSubLoops(List<List<Curve>> subLoops, List<Curve> oldLoop)
		{
			List<XYZ> vecPolypt = this.m_FloorEditCommon.GetverticesByPolygon(oldLoop);
			List<List<Curve>> list = new List<List<Curve>>();
			foreach (List<Curve> list2 in subLoops)
			{
				XYZ internalPoint = this.GetInternalPoint(list2);
				if (Geometry.PointInPloygon(vecPolypt, internalPoint, 0.0001, 0.0001) == 1 || Geometry.PointInPloygon(vecPolypt, internalPoint, 0.0001, 0.0001) == 0)
				{
					list.Add(list2);
				}
			}
			return list;
		}

		private XYZ GetInternalPoint(List<Curve> subLoop)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in subLoop)
			{
				list.Add(curve.GetEndPoint(0));
			}
			bool flag = Geometry.IsAntiClockwise(list);
			Curve curve2 = subLoop[0];
			XYZ hyendPoint = curve2.GetEndPoint(0);
			XYZ hyendPoint2 = curve2.GetEndPoint(1);
			XYZ xyz;
			if (curve2.GetType() == typeof(Arc))
			{
				Arc arc = curve2 as Arc;
				xyz = Geometry.CalculatMidPoint(hyendPoint, hyendPoint2, arc.Center, arc.Normal);
			}
			else
			{
				xyz = Geometry.CalculatMidPoint(hyendPoint, hyendPoint2);
			}
			XYZ xyz2 = (hyendPoint2 - hyendPoint).Normalize();
			xyz2 = Geometry.RotateTo(xyz2, -Math.PI*.5, XYZ.BasisZ);
			if (flag)
			{
				xyz2 = -xyz2;
			}
			xyz2 *= Common.MMToFeet(5.0);
			return xyz + xyz2;
		}

		private void CreateSubFloors(Floor floor, List<List<Curve>> includSubLoops, List<List<Curve>> openingLoops, List<List<Curve>> oldOpeningLoops)
		{
			FloorType floorType = null;
			Level level = null;
			double offset = 0.0;
			bool isStruct = false;
			this.m_FloorEditCommon.GetOldInfo(floor, ref floorType, ref level, ref offset, ref isStruct);
			List<Floor> list = new List<Floor>();
			List<List<Curve>> list2 = new List<List<Curve>>();
			foreach (List<Curve> list3 in includSubLoops)
			{
				if (!this.m_FloorEditCommon.floorInOpening(list3, oldOpeningLoops))
				{
					list2.Add(list3);
					Floor floor2 = this.m_FloorEditCommon.CreateFloor(list3, floorType, level, offset, isStruct);
					if (floor2 != null)
					{
						this.CopyParameters(floor, floor2);
						list.Add(floor2);
					}
				}
			}
			this.m_FloorEditCommon.NewOpeing(openingLoops, list2, list);
			this.m_FloorEditCommon.DeleteElement(floor);
		}

		private void CopyParameters(Floor floorS, Floor floorD)
		{
			Transaction transaction = null;
			try
			{
				transaction = new Transaction(this.m_doc);
				transaction.Start("copy parameters");
				foreach (object obj in floorS.Parameters)
				{
					Parameter parameter = (Parameter)obj;
					if (!parameter.IsReadOnly && !parameter.IsShared)
					{
						InternalDefinition internalDefinition = parameter.Definition as InternalDefinition;
						if (internalDefinition != null && internalDefinition.Name.CompareTo("标记") != 0 && internalDefinition.Name.CompareTo("Number") != 0)
						{
							try
							{
								switch ((int)parameter.StorageType)
								{
								case 1:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsInteger());
									break;
								case 2:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsDouble());
									break;
								case 3:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsString());
									break;
								case 4:
									floorD.GetParameter(internalDefinition.Name).Set(parameter.AsElementId());
									break;
								}
							}
							catch (Exception)
							{
							}
						}
					}
				}
				transaction.Commit();
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
			}
		}

		private List<List<Curve>> GetSplitCurveByBoundingbox(Floor floor, FilterType filterType, List<UtilityTools.ThicknessOfEdgeInfoEx> lstEdgeInfos)
		{
			List<Pole2D> list = new List<Pole2D>();
			BoundingBoxXYZ bounding = floor.get_BoundingBox(this.m_ActiveView);
			List<Element> selElements = new List<Element>();
			List<Element> selElements2 = new List<Element>();
			if ((filterType & FilterType.FT_Wall) != FilterType.FT_None)
			{
				this.GetWallList(bounding, ref selElements2);
			}
			if ((filterType & FilterType.FT_Grid) != FilterType.FT_None)
			{
				this.GetGridList(bounding, ref selElements);
			}
			if ((filterType & FilterType.FT_RefPlane) != FilterType.FT_None)
			{
				this.GetRefPlaneList(bounding, ref selElements);
			}
			if ((filterType & FilterType.FT_Beam) != FilterType.FT_None)
			{
				this.GetBeamList(bounding, ref selElements2);
			}
			List<Curve> list2 = new List<Curve>();
			this.FilterCurveFromElements(filterType, selElements, ref list2);
			List<Curve> lstCvs = new List<Curve>();
			this.FilterCurveFromElements(filterType, selElements2, ref lstCvs);
			List<Curve> splitCurves = UtilityTools.GetSplitCurves(lstCvs);
			list2.AddRange(splitCurves);
			foreach (Curve curve in list2)
			{
				Pole2D item = Pole2D.TransformWallToStructure2DPole(curve, null, 0.0, 0.0);
				list.Add(item);
			}
			new List<Curve>();
			new List<List<Curve>>();
			List<List<Curve>> list3 = new List<List<Curve>>();
			List<List<Curve>> list4 = new List<List<Curve>>();
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_Revit);
			foreach (List<Curve> lstCurves in structureLoopSearcher.GetCellsEdgeLoops(list, true))
			{
				List<KeyValuePair<Curve, double>> edgeLoop = UtilityTools.CreatePole2DWithThickness(this.m_doc, lstCurves, lstEdgeInfos);
				list3 = structureLoopSearcher.OffsetLoop(edgeLoop, true, true);
				if (list3.Count != 0)
				{
					list4.Add(list3[0]);
				}
			}
			return list4;
		}

		private void FilterCurveFromElements(FilterType filterType, List<Element> selElements, ref List<Curve> selCurves)
		{
			foreach (Element element in selElements)
			{
				if (element.GetType() == typeof(Wall) && (filterType & FilterType.FT_Wall) != FilterType.FT_None)
				{
					selCurves.Add((element.Location as LocationCurve).Curve);
				}
				else if (element.GetType() == typeof(Grid) && (filterType & FilterType.FT_Grid) != FilterType.FT_None)
				{
					selCurves.Add((element as Grid).Curve);
				}
				else if (element.GetType() == typeof(ReferencePlane) && (filterType & FilterType.FT_RefPlane) != FilterType.FT_None)
				{
					ReferencePlane referencePlane = element as ReferencePlane;
					XYZ startPoint = new XYZ(referencePlane.BubbleEnd.X, referencePlane.BubbleEnd.Y, 0.0);
					XYZ endPoint = new XYZ(referencePlane.FreeEnd.X, referencePlane.FreeEnd.Y, 0.0);
					selCurves.Add(YJKLineEx.YJKGetBound(startPoint, endPoint));
				}
				else if (element.GetType() == typeof(FamilyInstance) && (filterType & FilterType.FT_Beam) != FilterType.FT_None)
				{
					selCurves.Add((element.Location as LocationCurve).Curve);
				}
			}
			if ((filterType & FilterType.FT_Wall) != FilterType.FT_None || (filterType & FilterType.FT_Beam) != FilterType.FT_None)
			{
				selCurves.AddRange(this.m_InterimCurveList);
			}
		}

		private BoundingBoxIntersectsFilter GetBoundingBoxFilter(BoundingBoxXYZ bounding)
		{
			XYZ xyz = new XYZ(1.0, 1.0, 1.0);
			return new BoundingBoxIntersectsFilter(new Outline(bounding.Min - xyz, bounding.Max + xyz), false);
		}

		private void GetWallList(BoundingBoxXYZ bounding, ref List<Element> elements)
		{
			BoundingBoxIntersectsFilter boundingBoxFilter = this.GetBoundingBoxFilter(bounding);
			foreach (Element item in new FilteredElementCollector(this.m_doc, this.m_ActiveView.Id).OfClass(typeof(Wall)).WherePasses(boundingBoxFilter).ToElements())
			{
				elements.Add(item);
			}
		}

		private void GetGridList(BoundingBoxXYZ bounding, ref List<Element> elements)
		{
			foreach (Element element in new FilteredElementCollector(this.m_doc, this.m_ActiveView.Id).OfClass(typeof(Grid)).ToElements())
			{
				if (!(element.GetType() != typeof(Grid)))
				{
					elements.Add(element);
				}
			}
		}

		private void GetRefPlaneList(BoundingBoxXYZ bounding, ref List<Element> elements)
		{
			foreach (Element item in new FilteredElementCollector(this.m_doc, this.m_ActiveView.Id).OfClass(typeof(ReferencePlane)).ToElements())
			{
				elements.Add(item);
			}
		}

		private void GetBeamList(BoundingBoxXYZ bounding, ref List<Element> elements)
		{
			BoundingBoxIntersectsFilter boundingBoxFilter = this.GetBoundingBoxFilter(bounding);
			foreach (Element item in from elem in new FilteredElementCollector(this.m_doc, this.m_ActiveView.Id).OfClass(typeof(FamilyInstance)).WherePasses(boundingBoxFilter).ToElements()
			let familyInstance = elem as FamilyInstance
			where (int)familyInstance.StructuralType == 1
			select familyInstance)
			{
				elements.Add(item);
			}
		}

		private ExternalCommandData m_Revit;

		private Autodesk.Revit.DB.Document m_doc;

		private Autodesk.Revit.DB.View m_ActiveView;

		private FloorEditCommon m_FloorEditCommon;

		private List<Curve> m_InterimCurveList = new List<Curve>();
	}
}
